package cc.comac.saic.hkhy.jsrj.gj.inttools.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.gitlab4j.api.GitLabApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import cc.comac.saic.hkhy.jsrj.gj.inttools.constant.FileType;
import cc.comac.saic.hkhy.jsrj.gj.inttools.gitlab.VersionManegeClient;
import cc.comac.saic.hkhy.jsrj.gj.inttools.mapper.FileInfoMapper;
import cc.comac.saic.hkhy.jsrj.gj.inttools.mapper.FileVersionInfoMapper;
import cc.comac.saic.hkhy.jsrj.gj.inttools.mapper.ProjectInfoMapper;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.entity.FileInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.entity.FileVersionInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.entity.ProjectInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileInfoSearchVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileInfoShowVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileTypeStatVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileVersionShowVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.service.FileInfoService;
import cc.comac.saic.hkhy.jsrj.gj.inttools.service.IntToolDataInfoService;
import cn.hutool.core.collection.CollectionUtil;
import jakarta.servlet.http.Part;

/**
 * 文件信息(FileInfo)表服务实现类
 *
 * @author makejava
 * @since 2025-07-02 18:26:30
 */
@Service
public class FileInfoServiceImpl implements FileInfoService {
    @Autowired
    private ProjectInfoMapper projectInfoMapper;
    @Autowired
    private FileInfoMapper fileInfoMapper;
    @Autowired
    private FileVersionInfoMapper fileVersionInfoMapper;
    @Autowired
    private VersionManegeClient versionManegeClient;
    @Autowired
    private IntToolDataInfoService intToolDataInfoService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public FileInfo queryById(Long id) {
        return this.fileInfoMapper.queryById(id);
    }

    @Override
    public List<FileInfoShowVo> queryVersionByDataKey(String key) {
        List<FileInfo> fileInfos = fileInfoMapper.queryByKey(key);
        if (CollectionUtil.isEmpty(fileInfos)) {
            return null;
        }

        return fileInfos.stream().map(fileInfo -> {
            List<FileVersionInfo> fileVersionInfos = fileVersionInfoMapper.queryByFileId(fileInfo.getId());
            FileInfoShowVo fileInfoShowVo = new FileInfoShowVo();
            fileInfoShowVo.setId(fileInfo.getId());
            fileInfoShowVo.setDataKey(key);
            fileInfoShowVo.setProjId(fileInfo.getProjId());
            fileInfoShowVo.setPath(fileInfo.getFilePath());
            List<FileVersionShowVo> fileVersionShowVos = fileVersionInfos.stream()
                .map(fileVersionInfo -> new FileVersionShowVo(fileVersionInfo.getHash(), fileVersionInfo.getCreateTime()))
                .collect(Collectors.toList());
            fileInfoShowVo.setVersions(fileVersionShowVos);
            return fileInfoShowVo;
        }).collect(Collectors.toList());
    }

    /**
     * 分页查询
     *
     * @param fileInfo 筛选条件
     * @return 查询结果
     */
    @Override
    public List<FileInfo> queryByCondition(FileInfoSearchVo fileInfo) {
        return this.fileInfoMapper.queryByCondition(fileInfo);
    }

    @Override
    public List<FileInfo> queryProjectFile(String projKey, String fileType) {
        FileInfoSearchVo fileInfo = new FileInfoSearchVo();
        fileInfo.setProjKey(projKey);
        fileInfo.setFileType(fileType);
        return fileInfoMapper.queryByCondition(fileInfo);
    }

    /**
     * 新增数据
     *
     * @param fileInfo 实例对象
     * @return 实例对象
     */
    @Override
    public FileInfo insert(FileInfo fileInfo) {
        this.fileInfoMapper.insert(fileInfo);
        return fileInfo;
    }

    /**
     * 修改数据
     *
     * @param fileInfo 实例对象
     * @return 实例对象
     */
    @Override
    public FileInfo update(FileInfo fileInfo) {
        this.fileInfoMapper.update(fileInfo);
        return this.queryById(fileInfo.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.fileInfoMapper.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public List<FileInfoShowVo> upload(String projKey, FileType fileType, Collection<Part> fileParts, Long operator) {
        try {
            String commitHash = versionManegeClient.uploadFiles(projKey, fileType, fileParts);
            ProjectInfo projectInfo = projectInfoMapper.queryByKey(projKey);

            List<FileVersionInfo> fileVersionInfos = new ArrayList<>();
            List<FileInfoShowVo> fileInfoShowVos = fileParts.stream()
                .filter(part -> StringUtils.hasText(part.getSubmittedFileName()))
                .map(part -> {
                    FileInfoShowVo fileInfoShowVo = new FileInfoShowVo();
                    String originalFilePath = part.getSubmittedFileName();
                    FileInfo fileInfo = fileInfoMapper.queryByProjectIdAndFilePath(projectInfo.getId(), fileType.getCode(), originalFilePath);

                    if (Objects.isNull(fileInfo)) {
                        fileInfo = new FileInfo();
                        fileInfo.setFileKey(originalFilePath);
                        fileInfo.setFilePath(originalFilePath);
                        fileInfo.setFileType(fileType.getCode());
                        fileInfo.setProjId(projectInfo.getId());
                        fileInfoMapper.insert(fileInfo);
                    }

                    FileVersionInfo fileVersionInfo = fileVersionInfoMapper.queryLatestByFileId(fileInfo.getId());
                    String version = Optional.ofNullable(fileVersionInfo)
                        .map(FileVersionInfo::getVersion)
                        .map(ver -> String.valueOf(Integer.parseInt(ver) + 1))
                        .orElse("1");

                    fileVersionInfo = new FileVersionInfo();
                    fileVersionInfo.setFileInfoId(fileInfo.getId());
                    fileVersionInfo.setVersion(version);
                    fileVersionInfo.setHash(commitHash);
                    fileVersionInfoMapper.insert(fileVersionInfo);
                    fileVersionInfos.add(fileVersionInfo);

                    fileInfoShowVo.setId(fileInfo.getId());
                    fileInfoShowVo.setDataKey(fileInfo.getFileKey());
                    fileInfoShowVo.setPath(originalFilePath);
                    fileInfoShowVo.setVersions(Collections.singletonList(new FileVersionShowVo(commitHash, new Date())));
                    return fileInfoShowVo;
                }).collect(Collectors.toList());

            // 解析数据
            fileVersionInfos.forEach(fileVersionInfo -> intToolDataInfoService.parseAndSaveIntToolData(fileVersionInfo.getId(), operator));

            return fileInfoShowVos;
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public byte[] download(String projKey, String fileType, String filePath, String versionHash) {
        try {
            ProjectInfo projectInfo = projectInfoMapper.queryByKey(projKey);
            FileInfo fileInfo = fileInfoMapper.queryByProjectIdAndFilePath(projectInfo.getId(), fileType, filePath);

            // 如果versionHash为空，则查询最新版本
            if (!StringUtils.hasText(versionHash)) {
                versionHash = Optional.ofNullable(fileVersionInfoMapper.queryLatestByFileId(fileInfo.getId())).map(FileVersionInfo::getHash).orElseThrow();
            }

            return versionManegeClient.getFileBytes(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public byte[] downloadByFileId(Long fileId) {
        try {
            FileInfo fileInfo = fileInfoMapper.queryById(fileId);
            Long projId = fileInfo.getProjId();
            String fileType = fileInfo.getFileType();
            String filePath = fileInfo.getFilePath();
            ProjectInfo projectInfo = projectInfoMapper.queryById(projId);
            String projKey = projectInfo.getProjKey();

            // 则查询最新版本
            String versionHash = Optional.ofNullable(fileVersionInfoMapper.queryLatestByFileId(fileInfo.getId())).map(FileVersionInfo::getHash).orElseThrow();

            return versionManegeClient.getFileBytes(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public byte[] downloadByFileVersionId(Long fileVersionId) {
        try {
            FileVersionInfo fileVersionInfo = fileVersionInfoMapper.queryById(fileVersionId);
            Long fileId = fileVersionInfo.getFileInfoId();
            String versionHash = fileVersionInfo.getHash();
            FileInfo fileInfo = fileInfoMapper.queryById(fileId);
            Long projId = fileInfo.getProjId();
            String fileType = fileInfo.getFileType();
            String filePath = fileInfo.getFilePath();
            ProjectInfo projectInfo = projectInfoMapper.queryById(projId);
            String projKey = projectInfo.getProjKey();

            return versionManegeClient.getFileBytes(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String getContent(String projKey, String fileType, String filePath, String versionHash) {
        try {
            ProjectInfo projectInfo = projectInfoMapper.queryByKey(projKey);
            FileInfo fileInfo = fileInfoMapper.queryByProjectIdAndFilePath(projectInfo.getId(), fileType, filePath);

            // 如果versionHash为空，则查询最新版本
            if (!StringUtils.hasText(versionHash)) {
                versionHash = Optional.ofNullable(fileVersionInfoMapper.queryLatestByFileId(fileInfo.getId())).map(FileVersionInfo::getHash).orElseThrow();
            }

            return versionManegeClient.getFileContent(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String getContentByFileId(Long fileId) {
        try {
            FileInfo fileInfo = fileInfoMapper.queryById(fileId);
            Long projId = fileInfo.getProjId();
            String fileType = fileInfo.getFileType();
            String filePath = fileInfo.getFilePath();
            ProjectInfo projectInfo = projectInfoMapper.queryById(projId);
            String projKey = projectInfo.getProjKey();

            // 则查询最新版本
            String versionHash = Optional.ofNullable(fileVersionInfoMapper.queryLatestByFileId(fileInfo.getId())).map(FileVersionInfo::getHash).orElseThrow();

            return versionManegeClient.getFileContent(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String getContentByFileVersionId(Long fileVersionId) {
        try {
            FileVersionInfo fileVersionInfo = fileVersionInfoMapper.queryById(fileVersionId);
            Long fileId = fileVersionInfo.getFileInfoId();
            String versionHash = fileVersionInfo.getHash();
            FileInfo fileInfo = fileInfoMapper.queryById(fileId);
            Long projId = fileInfo.getProjId();
            String fileType = fileInfo.getFileType();
            String filePath = fileInfo.getFilePath();
            ProjectInfo projectInfo = projectInfoMapper.queryById(projId);
            String projKey = projectInfo.getProjKey();

            return versionManegeClient.getFileContent(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<FileTypeStatVo> getFileTypeStatsByProjectId(Long projId) {
        List<Map<String, Object>> rawStats = fileInfoMapper.countFileTypeByProjectId(projId);
        if (rawStats == null) return Collections.emptyList();
        return rawStats.stream()
            .map(map -> new FileTypeStatVo(
                String.valueOf(map.get("name")),
                ((Number) map.get("value")).intValue()
            ))
            .collect(java.util.stream.Collectors.toList());
    }
}
